function Token(text, type) {
    Object.defineProperty(this, 'text', {
        enumerable: true,
        value: text
    });
    Object.defineProperty(this, 'type', {
        enumerable: true,
        value: type
    });
}

function Simplexer(buffer) {
    var reg = /(\d+)|(true)|(false)|(\".*\")|([+\-*/%()=])|((if)|(else)|(for)|(while)|(return)|(func)|(and)|(break))|([\s\t\n\v\f]+)|([a-zA-Z$_][\w$]*)/g;
    this.tokens = [];
    this.index = -1;
    var exps = [
        { 'exp': /^\d+$/, 'type': 'integer' },
        { 'exp': /^(true)|(false)$/, 'type': 'boolean' },
        { 'exp': /^\".*\"$/, 'type': 'string' },
        { 'exp': /^[+\-*/%()=]$/, 'type': 'operator' },
        { 'exp': /^(if)|(else)|(for)|(while)|(return)|(func)|(and)|(break)$/, 'type': 'keyword' },
        { 'exp': /^[\s\t\n\v\f]+$/, 'type': 'whitespace' },
        { 'exp': /^[a-zA-Z$_][\w$]*$/, 'type': 'identifier' }
    ]

    var arr = buffer.match(reg) || [];
    for (var i = 0; i < arr.length; i++) {
        var x = arr[i];
        for (e of exps) {
            if (e.exp.test(x)) {
                this.tokens.push(new Token(x, e.type));
                break;
            }
        }
    }
    this.hasNext = function () {
        return this.index < this.tokens.length - 1 && this.tokens.length > 0;
    };

    this.next = function () {
        return this.tokens[++this.index];
    };

}
